#!/bin/zsh

# ======================================================================== barrier and define

# if not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

# include common
source $(realpath $(dirname "$0"))/common

# checkout shell type
if [ $SHELL_TYPE != 'zsh' ]; then
    log_error 'current shell is not Zsh!'
    return
fi

# ======================================================================== configuration by machine

# get mach
gen_mach='unknown_null'
case $OS in
    linux)
        gen_mach=$(hostname) ;;
    macos)
        gen_mach=$(echo $HOST | sed -E 's/[.][a-zA-Z]*//g') ;;
    windows)
        gen_mach=$(hostname) ;;
esac

# source mach
if [ -f ${GENZSHPATH}/mach/$gen_mach ]; then
    source ${GENZSHPATH}/mach/$gen_mach
else
    log_error 'machine not support!'
    return
fi

# ======================================================================== logo

printf "Welcome to %s (%s %s %s)\n" "$gen_mach" "$(uname -o)" "$(uname -r)" "$(uname -m)"
logo
printf "Hi %s, Have a nice day ~\n" "$(whoami)"

# ======================================================================== optional configuration for machine (source ~/.optional if it exist)

if [ -f ~/.optional ]; then
    source ~/.optional
fi

# ======================================================================== alias for quickstart

# ssh
alias matrix="ssh ${MATRIX_IP_PORT[1]}@${MATRIX_IP_PORT[2]} -p ${MATRIX_IP_PORT[3]}"
alias quantum="ssh ${QUANTUM_IP_PORT[1]}@${QUANTUM_IP_PORT[2]} -p ${QUANTUM_IP_PORT[3]}"
alias vos="ssh ${VOS_IP_PORT[1]}@${VOS_IP_PORT[2]} -p ${VOS_IP_PORT[3]}"
alias public="ssh ${PUBLIC_IP_PORT[1]}@${PUBLIC_IP_PORT[2]} -p ${PUBLIC_IP_PORT[3]}"

# git
alias gita='git add'
alias gitm='git commit -m'
alias gits='git status'
alias gitl='git log --graph'
alias gitll='git log --oneline --all --graph'
alias gitrl='git reflog'
alias gitb='git branch'
alias gitf='git diff'
alias gitc='git checkout'

# folder $WORKPATH
alias capplications="cd ${WORKPATH}/applications"
alias cdata="cd ${WORKPATH}/data"
alias cdownload="cd ${WORKPATH}/download"
alias cfield="cd ${WORKPATH}/field"
alias ctemporary="cd ${WORKPATH}/temporary"
alias cwork="cd ${WORKPATH}/work"
alias ctrash="cd ${WORKPATH}/trash"

# folder field
alias cstudy="cd ${WORKPATH}/field/gitee-elvis/Study"
alias ctcode="cd ${WORKPATH}/field/gitee-elvis/TestCode"
alias cccode="cd ${WORKPATH}/field/gitee-elvis/CaseCode"
alias cdpool="cd ${WORKPATH}/field/gitee-elvis/DataPool"
alias cdocuments="cd ${WORKPATH}/field/documents"
alias cdevelop="cd ${WORKPATH}/field/develop"
alias cnote="cd ${WORKPATH}/field/note"

# dif
if which code 1>/dev/null 2>&1; then
    alias dif='code --diff'
else
    alias dif='vimdiff'
fi

# system
if [ $OS = 'macos' ]; then
    alias ls='ls --color=auto'
    alias ll="ls -alF"
else
    alias ls='ls --color=auto --group-directories-first'
    alias ll="ls -alF --full-time"
fi
alias l="ls -lh"
alias grep='grep --color=auto'

# note
alias note="vim ${WORKPATH}/field/note/quick_note.md"

# ======================================================================== zsh configurations

# language setup
if locale -a | grep -o -i -E 'en_US.utf[-]?8' 1> /dev/null; then
    export LANG=$(locale -a | grep -o -i -E 'en_US.utf[-]?8')
elif locale -a | grep -o -i -E 'C.utf[-]?8' 1> /dev/null; then
    export LANG=$(locale -a | grep -o -i -E 'C.utf[-]?8')
elif locale -a | grep -o -i -E 'zh_CN.utf[-]?8' 1> /dev/null; then
    export LANG=$(locale -a | grep -o -i -E 'zh_CN.utf[-]?8')
else
    log_error 'No UFT-8 set in system'
    return
fi

# command prompt type: `user@hostname:path $`
function __exit_prompt () {
    local exit_code=$?
    local exit_prompt
    case $exit_code in
        0)      exit_prompt='😍' ;;     # successful
        1)      exit_prompt='😡' ;;     # normal error
        127)    exit_prompt='🤔' ;;     # undefined command
        130)    exit_prompt='🤡' ;;     # break
        *)      exit_prompt='😱' ;;     # others
    esac
    RPROMPT="$exit_prompt %D{%H:%M:%S}"
}
if [ "$SUPPORT_COLOR" = 'yes' ]; then
    PS1="%F{green}%n@%m%f:%F{blue}%~%F{magenta}%#%f "
    # RPROMPT='%(?.😍.😡) %F{magenta}%D{%H:%M:%S}%f'
    autoload -Uz add-zsh-hook
    add-zsh-hook precmd __exit_prompt
else
    PS1='%n@%m:%~%# '
    RPROMPT='[$?] %D{%H:%M:%S}'
fi

# history
HISTSIZE=200
SAVEHIST=200
HISTFILE=~/.zsh_history
setopt INC_APPEND_HISTORY
# setopt SHARE_HISTORY
setopt histignorealldups    # ignore repeat commands
setopt histignorespace      # don't record the command with start with space

# key map
source ${GENZSHPATH}/keymap

# complation
autoload -Uz compinit
compinit
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*'     # ignore case

# plugins configuration
for script in ${GENZSHPATH}/plugins/*.config.sh; do
    source "$script"
done

# ======================================================================== source os by os type

source ${GENZSHPATH}/${OS}

# ======================================================================== general functions

# del, move the specified file or dir to trash
if [ ! -d ${WORKPATH}/trash ]; then
    mkdir ${WORKPATH}/trash
fi
typeset -A del_list
function del () {
    if [ $# -eq 0 ]; then
        log_error 'nothing to specified'
        return 255
    fi
    # a flag for whether to clean del_list
    local cleaned_flag='n'
    for item in "$@"; do
        if [ -e "$item" ]; then
            if [ "$cleaned_flag" = 'n' ]; then
                cleaned_flag='y'
                del_list=()
            fi
            if [ "$(dirname "$(realpath "$item")")" = ${WORKPATH}/trash ]; then
                # remove from filesystem
                rm -rf "$item"
                console $COLR_F_YELLOW "[R ]: $item"
            else
                local del_msg='[D ]'
                # record
                del_list["$(basename "$item")"]="$(dirname "$(realpath "$item")")"
                # remove from trash if it is already exist
                if [ -e "${WORKPATH}/trash/$(basename "$item")" ]; then
                   rm -rf "${WORKPATH}/trash/$(basename "$item")"
                   del_msg='[RD]'
                fi
                # move it to trash
                mv "$item" ${WORKPATH}/trash
                console $COLR_F_YELLOW "$del_msg: $item"
            fi
        else
            log_warning "($item) not exist"
        fi
    done
}

# udel, undo del operation
function udel ()
{
    if [ $# -gt 1 ]; then
        log_error 'wrong number of arguments'
        return 255
    fi
    if [ $# -eq 1 ] && [ "$1" = 'l' ]; then
        # must be `k`, and can't use "" for `${(k)del_list}`
        for k in ${(k)del_list}; do
            console $COLR_F_YELLOW "$k -> ${del_list[$k]}"
        done
    else
        # recover
        for k in ${(k)del_list}; do
            if [ -e "${WORKPATH}/trash/$k" ]; then
                mv "${WORKPATH}/trash/$k" "${del_list[$k]}"
                console $COLR_F_YELLOW "[RECOVER]: $k"
            else
                log_warning "($k) deleted"
            fi
        done
        # clean del_list, it also can be associate array
        del_list=()
    fi
}

# upload(l1,l2,...,rdir), upload the specified file or dir to $SERVER_IP_PORT
function upload ()
{
    if [ $# -lt 2 ]; then
        log_error 'wrong number of arguments'
        return 255
    fi
    local from
    # get last value from $@
    local to=${@: -1}
    # replace $HOME to ~, need change / to \/ first in $HOME
    to=$(sed "s/$(sed 's/\//\\\//g' <<< $HOME)/\~/g" <<<$to)
    # substring (1~len-1) from $@, can't use `${@:1:$#-1}`
    local end=$(expr $# - 1)
    for item in "${@:1:$end}"; do
        if [ -e "$item" ]; then
            from="'$item' $from"
        else
            log_warning "($item) not exist"
        fi
    done
    if [ "$from" != '' ]; then
        echo "-P ${SERVER_IP_PORT[3]} -r $from ${SERVER_IP_PORT[1]}@${SERVER_IP_PORT[2]}:$to" | xargs scp
    fi 
}

# download(r,ldir), download the specified file or dir from $SERVER_IP_PORT
function download ()
{
    if [ $# -gt 2 ] || [ $# -lt 1 ]; then
        log_error 'wrong number of arguments'
        return 255
    fi
    local from=$1
    local to=.
    if [ $# -eq 2 ]; then
        to=$2
    fi
    # replace $HOME to ~, need change / to \/ first in $HOME
    from=$(sed "s/$(sed 's/\//\\\//g' <<< $HOME)/\~/g" <<<$from)
    scp -P ${SERVER_IP_PORT[3]} -r ${SERVER_IP_PORT[1]}@${SERVER_IP_PORT[2]}:$from $to
}
